home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 22 code / Futures / FutureShock / AppleEventUtilities.cp < prev    next >
Encoding:
Text File  |  1995-04-14  |  74.0 KB  |  2,241 lines  |  [TEXT/MMCC]

  1. /*
  2.     File:        AppleEventUtilities.cp
  3.  
  4.     Contains:    C++ Wrappers for Apple Event manager
  5.  
  6. */
  7.  
  8. #ifndef __APPLEEVENTUTILITIES__
  9. #include "AppleEventUtilities.h"
  10. #endif
  11.  
  12. #ifndef __ASREGISTRY__
  13. #include <ASRegistry.h>
  14. #endif
  15.  
  16. #ifndef Exceptions_h
  17. #include "Exceptions.h"
  18. #endif
  19.  
  20. #ifndef __OSUTILS__
  21. #include <OSUtils.h>
  22. #endif
  23.  
  24. #ifndef __SCRIPT__
  25. #include <Script.h>
  26. #endif
  27.  
  28. #ifndef __APPLEEVENTS__
  29. #include <AppleEvents.h>
  30. #endif
  31.  
  32. #ifndef __AEOBJECTS__
  33. #include <AEObjects.h>
  34. #endif
  35.  
  36. #ifndef __ALIASES__
  37. #include <Aliases.h>
  38. #endif
  39.  
  40. #ifndef __AEOBJECTPACKING__
  41. #include <AEPackObject.h>
  42. #endif
  43.  
  44. #ifndef __AEREGISTRY__
  45. #include <AERegistry.h>
  46. #endif
  47.  
  48. #ifndef __GESTALTEQU__
  49. #include <GestaltEqu.h>
  50. #endif
  51.  
  52. //
  53. // Needed only by TAEvent::Ask
  54. //
  55. #ifndef __FUTURES__
  56. #include "Futures.h"
  57. #endif
  58.  
  59. #pragma segment AEMStuff
  60.  
  61.  
  62. MakeTokenDescriptorProcPtr gNullContainerCreationProc = nil;
  63. ProcessDescriptorProcPtr gPreResolveProc = nil;
  64. MergeTokensProcPtr gMergeTokensProc = nil;
  65.  
  66. short TDescriptor::fCallbackFlags = kAEIDoMinimum;
  67.  
  68. //----------------------------------------------------------------------------------------
  69. // InstallNullContainerCreationProc: 
  70. //
  71. // The null container creation proc is used by TDescriptor::Resolve whenever it receives
  72. // a null descriptor to resolve.  This function is used to create a token for the null
  73. // container.
  74. //----------------------------------------------------------------------------------------
  75. void InstallNullContainerCreationProc(MakeTokenDescriptorProcPtr creationProc)
  76.     {
  77.     gNullContainerCreationProc = creationProc;
  78.     } // InstallNullContainerCreationProc 
  79.  
  80. //----------------------------------------------------------------------------------------
  81. // InstallPreResolveProc: 
  82. //
  83. // The PreResolveProc is called by TDescriptor::Resolve before it actually calls
  84. // AEResolve.  This allows special procs to handle things not understood by AEResolve
  85. // (alias records, for example).
  86. //----------------------------------------------------------------------------------------
  87. void InstallPreResolveProc(ProcessDescriptorProcPtr preResolveProc)
  88.     {
  89.     gPreResolveProc = preResolveProc;
  90.     } // InstallPreResolveProc 
  91.  
  92. //----------------------------------------------------------------------------------------
  93. // InstallMergeTokensProc: 
  94. //
  95. // The MergeTokensProc is called by TTokenDescriptor::AdoptToken whenever it needs to add
  96. // a token object to any token descriptor that already contains a token.  The merge token
  97. // proc is provided with two TAbstractScriptableObject*'s; it must return a
  98. // TAbstractScriptableObject* that has adopted the two tokens passed to it.
  99. //----------------------------------------------------------------------------------------
  100. void InstallMergeTokensProc(MergeTokensProcPtr mergeTokensProc)
  101.     {
  102.     gMergeTokensProc = mergeTokensProc;
  103.     } // InstallMergeTokensProc 
  104.  
  105. //----------------------------------------------------------------------------------------
  106. // CreateNullContainerToken: 
  107. //----------------------------------------------------------------------------------------
  108. TTokenDescriptor CreateNullContainerToken()
  109.     {
  110.     TTokenDescriptor nullContainer;
  111.     
  112.     if(gNullContainerCreationProc != nil)
  113.         nullContainer = (*gNullContainerCreationProc)();
  114.     
  115.     return nullContainer;
  116.     } // CreateNullContainerToken 
  117.  
  118. //========================================================================================
  119. // CLASS TDescriptor
  120. //
  121. // Class TDescriptor is a wrapper class for AEDesc objects.
  122. //========================================================================================
  123.  
  124.  
  125. //----------------------------------------------------------------------------------------
  126. // TDescriptor::Dispose:
  127. //
  128. // Disposed of the descriptor and the data stored inside it.
  129. //----------------------------------------------------------------------------------------
  130. void TDescriptor::Dispose()
  131.     {
  132.     FailErr(AEDisposeDesc(*this));
  133.     } // TDescriptor::Dispose 
  134.  
  135. //----------------------------------------------------------------------------------------
  136. // TDescriptor::AttemptCoercion:
  137. //
  138. // Try to coerce the type of the descriptor to something else.  This method will
  139. // NOT fail if the coercion could not be done.
  140. //----------------------------------------------------------------------------------------
  141. OSErr TDescriptor::AttemptCoercion(DescType typeToCoerceTo)
  142.     {
  143.     OSErr err = noErr;
  144.     
  145.     if(this->DescriptorType() != typeToCoerceTo)
  146.         {
  147.         TDescriptor tempDescriptor;
  148.         
  149.         // If AECoerceDesc returns a non-zero result code, then
  150.         // tempDescriptor will be typeNull, and we don't need to
  151.         // worry about disposing of it.
  152.         err = AECoerceDesc(*this,typeToCoerceTo,(AEDesc*)&tempDescriptor);
  153.  
  154.         if(err == noErr)
  155.             {            
  156.             Try
  157.                 {
  158.                 Handle initialHandle = this->DataHandle();
  159.                 Handle coercedHandle = tempDescriptor.DataHandle();
  160.                 
  161.                 //
  162.                 // If doing a coerce-in-place, try to do a SetHandleSize
  163.                 // and then a BlockMove so that we end up using the same
  164.                 // handle when we exit as we had when we entered.  To do
  165.                 // otherwise is to invite double-dispose/memory leak problems
  166.                 // if some other peice of code still has a reference to
  167.                 // the descriptor before it was coerced
  168.                 //
  169.                 if((initialHandle != nil) && (coercedHandle != nil))
  170.                     {
  171.                     Size coercedSize = GetHandleSize(coercedHandle);
  172.                     SetHandleSize(initialHandle, coercedSize);
  173.                     FailErr(MemError());
  174.                     BlockMove(*coercedHandle, *initialHandle, coercedSize);
  175.                     this->fDescriptorType = tempDescriptor.DescriptorType();
  176.                     tempDescriptor.Dispose();
  177.                     }
  178.                 //
  179.                 // There are a couple of rare cases (typeTrue and typeFalse)
  180.                 // where the data handle is nil
  181.                 //
  182.                 else
  183.                     {
  184.                     //
  185.                     // It's undesirable to go from a nil-handle to a non-nil
  186.                     // handle, or visa-versa.  Don't do it.  Use 'Coerce'
  187.                     // rather than 'CoerceInPlace' if this is necessary.
  188.                     //
  189.                     if((initialHandle != nil) || (coercedHandle != nil))
  190.                         DebugStr("\pPotentially undesirable coerce-in-place");
  191.                     //
  192.                     // Try to dispose of the old descriptor (ignoring errors)
  193.                     // and then plug in the values from the coerced descriptor
  194.                     //
  195.                     AEDisposeDesc(*this);
  196.                     this->AdoptDesc(tempDescriptor);
  197.                     }
  198.                 }
  199.             Catch(err)
  200.                 {
  201.                 tempDescriptor.Dispose();
  202.                 }
  203.             }
  204.         }
  205.     
  206.     return err;
  207.     } // TDescriptor::AttemptCoercion 
  208.  
  209. //----------------------------------------------------------------------------------------
  210. // TDescriptor::CoerceInPlace:
  211. //
  212. // Require that this object be coerced to the specified data type.  This method will
  213. // fail if the coercion does not work.
  214. //----------------------------------------------------------------------------------------
  215. void TDescriptor::CoerceInPlace(DescType typeToCoerceTo)
  216.     {
  217.     FailErr(this->AttemptCoercion(typeToCoerceTo));
  218.     } // TDescriptor::CoerceInPlace 
  219.  
  220. //----------------------------------------------------------------------------------------
  221. // TDescriptor::Coerce:
  222. //
  223. // Require that this object be coerced to the specified data type.  This method will
  224. // fail if the coercion does not work.
  225. //----------------------------------------------------------------------------------------
  226. TDescriptor TDescriptor::Coerce(DescType typeToCoerceTo) const
  227.     {
  228.     TDescriptor coercedDescriptor;
  229.     
  230.     FailErr(AECoerceDesc(*this,typeToCoerceTo,coercedDescriptor));
  231.     
  232.     return coercedDescriptor;
  233.     } // TDescriptor::Coerce 
  234.     
  235. //----------------------------------------------------------------------------------------
  236. // TDescriptor::CoerceToStandardType:
  237. //
  238. // This method attempts to coerce its data into some form of standard type
  239. // (e.g. typeChar or typeLongInteger).  It is really annoying that someone can
  240. // invent yet another data type that is coercable to text or as a long integer,
  241. // but we wouldn't have any way to know that such a coercion should be attempted.
  242. // typeMagnitude and typeEnumeration could throw us for a loop too.
  243. //
  244. // ••• In short, I really hate this routine, but I'm not sure what else to do about it.
  245. //----------------------------------------------------------------------------------------
  246. void TDescriptor::CoerceToStandardType()
  247.     {
  248.     switch(this->DescriptorType())
  249.         {
  250.         case typeAEText:
  251.         case typeIntlText:
  252.         case typeStyledText:
  253.             {
  254.             this->CoerceInPlace(typeChar);
  255.             break;
  256.             }
  257.         
  258.         case typeShortInteger:
  259.             {
  260.             this->CoerceInPlace(typeLongInteger);
  261.             break;
  262.             }
  263.         }
  264.     } // TDescriptor::CoerceToStandardType 
  265.     
  266. //----------------------------------------------------------------------------------------
  267. // TDescriptor::Clone:
  268. //
  269. // Return an exact copy of this descriptor
  270. //----------------------------------------------------------------------------------------
  271. TDescriptor TDescriptor::Clone() const
  272.     {
  273.     TDescriptor clonedDescriptor;
  274.     
  275.     FailErr(AEDuplicateDesc(*this, (AEDesc*)&clonedDescriptor));
  276.     
  277.     return clonedDescriptor;
  278.     } // TDescriptor::Clone 
  279.  
  280. //----------------------------------------------------------------------------------------
  281. // TDescriptor::CopyDesc: 
  282. //----------------------------------------------------------------------------------------
  283. void TDescriptor::CopyDesc(const TDescriptor& desc)
  284.     {
  285.     FailErr(AEDuplicateDesc((AEDesc*)&desc, *this));
  286.     } // TDescriptor::CopyDesc 
  287.  
  288. //----------------------------------------------------------------------------------------
  289. // TDescriptor::AdoptDesc: 
  290. //----------------------------------------------------------------------------------------
  291. void TDescriptor::AdoptDesc(TDescriptor& desc)
  292.     {
  293.     //
  294.     // It would be very tempting to set 'desc' to the null descriptor now
  295.     // that we have adopted it here.  That would be a bad idea, though, because
  296.     // we might intend this descriptor to actually be just a reference to
  297.     // the adopted desc, and not actually the new 'owner' of the data.
  298.     //
  299.     this->AdoptHandle(desc.DescriptorType(), desc.DataHandle());
  300.     } // TDescriptor::AdoptDesc 
  301.  
  302. //----------------------------------------------------------------------------------------
  303. // TDescriptor::CreateList:
  304. //
  305. // Create an empty descriptor list or AERecord with factored data.
  306. //
  307. // n.b.    It is better to call MakeList, MakeEmptyList or MakeAERecord rather than
  308. // using TDescriptor::CreateList directly.
  309. //----------------------------------------------------------------------------------------
  310. void TDescriptor::CreateList(Boolean isRecord, Ptr factoringPtr, Size factoredSize)
  311.     {
  312.     FailErr(AECreateList(factoringPtr, factoredSize, isRecord, *this));
  313.     } // TDescriptor::CreateList 
  314.  
  315. //----------------------------------------------------------------------------------------
  316. // TDescriptor::MakeNull: 
  317. //----------------------------------------------------------------------------------------
  318. void TDescriptor::MakeNull()
  319.     {
  320.     this->AdoptHandle(typeNull, nil);
  321.     } // TDescriptor::MakeNull 
  322.  
  323. //----------------------------------------------------------------------------------------
  324. // TDescriptor::AdoptHandle:
  325. //
  326. // Assign some data and a type directly to the descriptor
  327. //----------------------------------------------------------------------------------------
  328. void TDescriptor::AdoptHandle(DescType dataType, Handle dataHandle)
  329.     {
  330.     fDescriptorType = dataType;
  331.     fDataHandle = dataHandle;
  332.     } // TDescriptor::AdoptHandle
  333.  
  334. //----------------------------------------------------------------------------------------
  335. // TDescriptor::CopyData: 
  336. //----------------------------------------------------------------------------------------
  337. void TDescriptor::CopyData(const DescType typeCode, const Ptr data, const Size length)
  338.     {
  339.     FailErr(AECreateDesc(typeCode, data, length, *this));
  340.     } // TDescriptor::CopyData 
  341.  
  342. //----------------------------------------------------------------------------------------
  343. // TDescriptor::MakeBoolean: 
  344. //----------------------------------------------------------------------------------------
  345. void TDescriptor::MakeBoolean(const Boolean data)
  346.     {
  347.     this->CopyData(typeBoolean, (Ptr)&data, sizeof(Boolean));
  348.     } // TDescriptor::MakeBoolean 
  349.     
  350. //----------------------------------------------------------------------------------------
  351. // TDescriptor::MakeLong: 
  352. //----------------------------------------------------------------------------------------
  353. void TDescriptor::MakeLong(const long data)
  354.     {
  355.     this->CopyData(typeLongInteger, (Ptr)&data, sizeof(long));
  356.     } // TDescriptor::MakeLong
  357.  
  358. //----------------------------------------------------------------------------------------
  359. // TDescriptor::MakeUnsignedLong: 
  360. //----------------------------------------------------------------------------------------
  361. void TDescriptor::MakeUnsignedLong(const unsigned long data)
  362.     {
  363.     this->CopyData(typeMagnitude, (Ptr)&data, sizeof(unsigned long));
  364.     } // TDescriptor::MakeUnsignedLong
  365.  
  366. //----------------------------------------------------------------------------------------
  367. // TDescriptor::MakeEnumeration: 
  368. //----------------------------------------------------------------------------------------
  369. void TDescriptor::MakeEnumeration(const DescType enumeration)
  370.     {
  371.     this->CopyData(typeEnumeration, (Ptr)&enumeration, sizeof(enumeration));
  372.     } // TDescriptor::MakeEnumeration 
  373.  
  374. //----------------------------------------------------------------------------------------
  375. // TDescriptor::MakeDescType: 
  376. //----------------------------------------------------------------------------------------
  377. void TDescriptor::MakeDescType(const DescType data)
  378.     {
  379.     this->CopyData(typeType, (Ptr)&data, sizeof(DescType));
  380.     } // TDescriptor::MakeDescType 
  381.  
  382. //----------------------------------------------------------------------------------------
  383. // TDescriptor::MakeKeyword: 
  384. //----------------------------------------------------------------------------------------
  385. void TDescriptor::MakeKeyword(const AEKeyword theKeyword)
  386.     {
  387.     this->CopyData(typeKeyword, (Ptr)&theKeyword, sizeof(AEKeyword));
  388.     } // TDescriptor::MakeKeyword 
  389.  
  390. //----------------------------------------------------------------------------------------
  391. // TDescriptor::MakeOrdinal: 
  392. //----------------------------------------------------------------------------------------
  393. void TDescriptor::MakeOrdinal(const DescType data)
  394.     {
  395.     this->CopyData(typeAbsoluteOrdinal, (Ptr)&data, sizeof(DescType));
  396.     } // TDescriptor::MakeOrdinal 
  397.     
  398. //----------------------------------------------------------------------------------------
  399. // TDescriptor::MakeTypeOrInteger:
  400. //
  401. // This is useful for debugging; it makes a 'type' if the data
  402. // appears to consist of printable characters (e.g. 'ABCD'), but
  403. // otherwise it makes an integer (e.g. -12).
  404. //----------------------------------------------------------------------------------------
  405. void TDescriptor::MakeTypeOrInteger(const DescType data)
  406.     {
  407.     if(((data >= 'A000') && (data <= 'Zzzz')) || ((data >= 'a000') && (data <= 'zzzz')))
  408.         this->MakeDescType(data);
  409.     else
  410.         this->MakeLong(data);
  411.     } // TDescriptor::MakeTypeOrInteger 
  412.  
  413. //----------------------------------------------------------------------------------------
  414. // TDescriptor::MakePoint: 
  415. //----------------------------------------------------------------------------------------
  416. void TDescriptor::MakePoint(const Point& thePoint)
  417.     {
  418.     this->CopyData(typeQDPoint, (Ptr)&thePoint, sizeof(Point));
  419.     } // TDescriptor::MakePoint 
  420.  
  421. //----------------------------------------------------------------------------------------
  422. // TDescriptor::MakePoint: 
  423. //----------------------------------------------------------------------------------------
  424. void TDescriptor::MakePoint(const short h, const short v)
  425.     {
  426.     Point thePoint;
  427.     
  428.     thePoint.v = v;
  429.     thePoint.h = h;
  430.     this->MakePoint(thePoint);
  431.     } // TDescriptor::MakePoint 
  432.  
  433. //----------------------------------------------------------------------------------------
  434. // TDescriptor::MakeRect: 
  435. //----------------------------------------------------------------------------------------
  436. void TDescriptor::MakeRect(const Rect& theRect)
  437.     {
  438.     this->CopyData(typeQDRectangle, (Ptr)&theRect, sizeof(Rect));
  439.     } // TDescriptor::MakeRect 
  440.  
  441. //----------------------------------------------------------------------------------------
  442. // TDescriptor::MakeString: 
  443. //----------------------------------------------------------------------------------------
  444. void TDescriptor::MakeString(Str255 data)
  445.     {
  446.     Size length = data[0];
  447.     
  448.     this->CopyData(typeChar, (Ptr)&data[1], length);
  449.     } // TDescriptor::MakeString 
  450.  
  451. //----------------------------------------------------------------------------------------
  452. // TDescriptor::MakeDateTimeRec: 
  453. //----------------------------------------------------------------------------------------
  454. void TDescriptor::MakeDateTimeRec(const DateTimeRec dateTime)
  455.     {
  456.     this->CopyData(typeDateTimeRec, (Ptr)&dateTime, sizeof(DateTimeRec));
  457.     } // TDescriptor::MakeDateTimeRec 
  458.  
  459. //----------------------------------------------------------------------------------------
  460. // TDescriptor::MakeDateTimeRec: 
  461. //----------------------------------------------------------------------------------------
  462. void TDescriptor::MakeDateTimeRec(const long secsSince1904)
  463.     {
  464.     DateTimeRec dateTime;
  465.     
  466.     //
  467.     // Let the OSUtilities do the hard work of converting seconds
  468.     // since 1904 into a DateTimeRec
  469.     //
  470.     Secs2Date(secsSince1904,&dateTime);
  471.     this->MakeDateTimeRec(dateTime);
  472.     } // TDescriptor::MakeDateTimeRec 
  473.  
  474. //----------------------------------------------------------------------------------------
  475. // TDescriptor::MakeLongDateTimeRec: 
  476. //----------------------------------------------------------------------------------------
  477. void TDescriptor::MakeLongDateTimeRec(const LongDateRec dateTime)
  478.     {
  479.     this->CopyData(typeLongDateTimeRec, (Ptr)&dateTime, sizeof(LongDateRec));
  480.     } // TDescriptor::MakeLongDateTimeRec 
  481.  
  482. //----------------------------------------------------------------------------------------
  483. // TDescriptor::MakeLongDateTimeRec: 
  484. //----------------------------------------------------------------------------------------
  485. void TDescriptor::MakeLongDateTimeRec(const DateTimeRec dateTime)
  486.     {
  487.     LongDateRec longDateTime;
  488.         
  489.     longDateTime.od.eraAlt = 0;
  490.     longDateTime.od.oldDate = dateTime;
  491.     
  492.     this->MakeLongDateTimeRec(longDateTime);
  493.     } // TDescriptor::MakeLongDateTimeRec 
  494.  
  495. //----------------------------------------------------------------------------------------
  496. // TDescriptor::MakeLongDateTimeRec: 
  497. //----------------------------------------------------------------------------------------
  498. void TDescriptor::MakeLongDateTimeRec(LongDateTime lsecs)
  499.     {
  500.     LongDateRec longDateTime;
  501.     
  502.     LongSecs2Date(&lsecs, &longDateTime);
  503.     this->MakeLongDateTimeRec(longDateTime);
  504.     } // TDescriptor::MakeLongDateTimeRec 
  505.  
  506. //----------------------------------------------------------------------------------------
  507. // TDescriptor::MakeLongDateTime: 
  508. //----------------------------------------------------------------------------------------
  509. void TDescriptor::MakeLongDateTime(const LongDateTime lsecs)
  510.     {
  511.     this->CopyData(typeLongDateTime, (Ptr)&lsecs, sizeof(LongDateTime));
  512.     } // TDescriptor::MakeLongDateTime 
  513.  
  514. //----------------------------------------------------------------------------------------
  515. // TDescriptor::MakeFSS: 
  516. //----------------------------------------------------------------------------------------
  517. void TDescriptor::MakeFSS(const FSSpec& spec)
  518.     {
  519.     this->CopyData(typeFSS, (Ptr)&spec, sizeof(FSSpec));
  520.     } // TDescriptor::MakeFSS 
  521.  
  522. //----------------------------------------------------------------------------------------
  523. // TDescriptor::AdoptAlias: 
  524. //
  525. // Takes the provided alias handle and keeps it forever.
  526. //----------------------------------------------------------------------------------------
  527. void TDescriptor::AdoptAlias(Handle alias)
  528.     {
  529.     this->AdoptHandle(typeAlias, alias);
  530.     } // TDescriptor::AdoptAlias 
  531.     
  532. //----------------------------------------------------------------------------------------
  533. // TDescriptor::MakeAlias: 
  534. //
  535. // You would think that someone would have spent five minutes to make a coercion
  536. // handler that goes from FSSpecs to Alias records, but nooooooo...
  537. //----------------------------------------------------------------------------------------
  538. void TDescriptor::MakeAlias(FSSpec& spec)
  539.     {
  540.     AliasHandle alias;
  541.     
  542.     FailErr(NewAliasMinimal(&spec, &alias));
  543.     this->AdoptAlias((Handle)alias);
  544.     } // TDescriptor::MakeAlias 
  545.  
  546. //----------------------------------------------------------------------------------------
  547. // TDescriptor::MakeProcessSerialNumber: 
  548. //----------------------------------------------------------------------------------------
  549. void TDescriptor::MakeProcessSerialNumber(ProcessSerialNumber psn)
  550.     {
  551.     this->CopyData(typeProcessSerialNumber, (Ptr)&psn, sizeof(ProcessSerialNumber));
  552.     } // TDescriptor::MakeProcessSerialNumber 
  553.  
  554. //----------------------------------------------------------------------------------------
  555. // TDescriptor::MakeObjectSpecifier: 
  556. //----------------------------------------------------------------------------------------
  557. void TDescriptor::MakeObjectSpecifier(DescType desiredClass, TDescriptor container, DescType keyForm, TDescriptor keyData, Boolean disposeInputs)
  558.     {
  559.     FailErr(CreateObjSpecifier(desiredClass,container,keyForm,keyData,disposeInputs,*this));
  560.     } // TDescriptor::MakeObjectSpecifier 
  561.  
  562. //----------------------------------------------------------------------------------------
  563. // TDescriptor::MakeCompDescriptor: 
  564. //----------------------------------------------------------------------------------------
  565. void TDescriptor::MakeCompDescriptor(DescType comparisonOperator, DescType propertyIdentifier, TDescriptor compareWith, Boolean disposeInputs)
  566.     {
  567.     TDescriptor operand1;
  568.     TDescriptor propertyIDDesc;
  569.     TDescriptor objectBeingExamined;
  570.     
  571.     //
  572.     // 'objectBeingExamined' is a special object specifier that only
  573.     // has meaning in the context of a comparison descriptor
  574.     //
  575.     objectBeingExamined.AdoptHandle(typeObjectBeingExamined,nil);
  576.     
  577.     //
  578.     // Operand1 is "fPropertyIdentifier of (object being examined)"
  579.     //
  580.     propertyIDDesc.MakeDescType(propertyIdentifier);
  581.     operand1.MakeObjectSpecifier(cProperty, objectBeingExamined, formPropertyID, propertyIDDesc, true);
  582.  
  583.     //
  584.     // Make a compDescriptor of operand1 compared with (fComparisonOperator) fCompareWith
  585.     //
  586.     CreateCompDescriptor(comparisonOperator, operand1, compareWith, disposeInputs, *this);
  587.     } // TDescriptor::MakeCompDescriptor 
  588.  
  589. //----------------------------------------------------------------------------------------
  590. // TDescriptor::GetBlock: 
  591. //----------------------------------------------------------------------------------------
  592. void TDescriptor::GetBlock(Ptr data, Size length, DescType desiredType) const
  593.     {
  594.     if(this->DataHandleIsNil())
  595.         FailErr(errAECantSupplyType);
  596.     
  597.     if(this->DescriptorType() != desiredType)
  598.         {
  599.         TDescriptor coerceData;
  600.         
  601.         coerceData = this->Coerce(desiredType);
  602.         coerceData.GetBlock(data,length,desiredType);
  603.         coerceData.Dispose();
  604.         }
  605.     else
  606.         {
  607.         //
  608.         // It would be just wrong to have a situation where a
  609.         // descriptor is of the requested type, but not of the
  610.         // requested length.  This method is only usable for
  611.         // fixed-size blocks
  612.         //
  613.         if(GetHandleSize(fDataHandle) != length)
  614.             {
  615.             FailErr(errAECorruptData);
  616.             }
  617.  
  618.         BlockMove(*fDataHandle, data, length);
  619.         }
  620.     } // TDescriptor::GetBlock 
  621.  
  622. //----------------------------------------------------------------------------------------
  623. // TDescriptor::GetLong: 
  624. //----------------------------------------------------------------------------------------
  625. long TDescriptor::GetLong() const
  626.     {
  627.     long result = 0;
  628.  
  629.     this->GetBlock((Ptr)&result, sizeof(long), typeLongInteger);
  630.  
  631.     return result;
  632.     } // TDescriptor::GetLong 
  633.     
  634. //----------------------------------------------------------------------------------------
  635. // TDescriptor::GetBoolean: 
  636. //----------------------------------------------------------------------------------------
  637. Boolean TDescriptor::GetBoolean() const
  638.     {
  639.     Boolean result = 0;
  640.  
  641.     this->GetBlock((Ptr)&result, sizeof(Boolean), typeBoolean);
  642.  
  643.     return result;
  644.     } // TDescriptor::GetBoolean 
  645.  
  646. //----------------------------------------------------------------------------------------
  647. // TDescriptor::GetDescType: 
  648. //----------------------------------------------------------------------------------------
  649. DescType TDescriptor::GetDescType() const
  650.     {
  651.     DescType result = 0;
  652.     
  653.     this->GetBlock((Ptr)&result, sizeof(DescType), typeType);
  654.     
  655.     return result;
  656.     } // TDescriptor::GetDescType 
  657.  
  658. //----------------------------------------------------------------------------------------
  659. // TDescriptor::GetKeyword: 
  660. //----------------------------------------------------------------------------------------
  661. AEKeyword TDescriptor::GetKeyword() const
  662.     {
  663.     AEKeyword result = 0;
  664.     
  665.     this->GetBlock((Ptr)&result, sizeof(AEKeyword), typeKeyword);
  666.     
  667.     return result;
  668.     } // TDescriptor::GetKeyword 
  669.     
  670. //----------------------------------------------------------------------------------------
  671. // TDescriptor::GetEnumeration: 
  672. //----------------------------------------------------------------------------------------
  673. DescType TDescriptor::GetEnumeration() const
  674.     {
  675.     DescType result = 0;
  676.     
  677.     this->GetBlock((Ptr)&result, sizeof(DescType), typeEnumeration);
  678.     
  679.     return result;
  680.     } // TDescriptor::GetEnumeration 
  681.  
  682. //----------------------------------------------------------------------------------------
  683. // TDescriptor::GetOrdinal: 
  684. //----------------------------------------------------------------------------------------
  685. DescType TDescriptor::GetOrdinal() const
  686.     {
  687.     DescType result = 0;
  688.     
  689.     this->GetBlock((Ptr)&result, sizeof(DescType), typeAbsoluteOrdinal);
  690.     
  691.     return result;
  692.     } // TDescriptor::GetOrdinal 
  693.  
  694. //----------------------------------------------------------------------------------------
  695. // TDescriptor::GetPoint: 
  696. //----------------------------------------------------------------------------------------
  697. Point TDescriptor::GetPoint() const
  698.     {
  699.     Point result;
  700.  
  701.     this->GetBlock((Ptr)&result, sizeof(Point), typeQDPoint);
  702.  
  703.     return result;
  704.     } // TDescriptor::GetPoint 
  705.  
  706. //----------------------------------------------------------------------------------------
  707. // TDescriptor::GetRect: 
  708. //----------------------------------------------------------------------------------------
  709. Rect TDescriptor::GetRect() const
  710.     {
  711.     Rect result;
  712.  
  713.     this->GetBlock((Ptr)&result, sizeof(Rect), typeQDRectangle);
  714.     
  715.     return result;
  716.     } // TDescriptor::GetRect 
  717.  
  718. //----------------------------------------------------------------------------------------
  719. // TDescriptor::GetString: 
  720. //----------------------------------------------------------------------------------------
  721. void TDescriptor::GetString(Str255 result) const
  722.     {
  723.     result[0] = 0;
  724.  
  725.     if(this->DataHandleIsNil())
  726.         FailErr(errAECantSupplyType);
  727.         
  728.     if(this->DescriptorType() == typeChar)
  729.         {
  730.         Size length = GetHandleSize(fDataHandle);
  731.         if(length > 255)
  732.             length = 255;
  733.         BlockMove(*fDataHandle, (Ptr)&result[1], length);
  734.         result[0] = (unsigned char) length;
  735.         }
  736.     else
  737.         {
  738.         TDescriptor makeDataString;
  739.         
  740.         makeDataString = this->Coerce(typeChar);
  741.         ASSERT(makeDataString.DescriptorType() == typeChar);
  742.         makeDataString.GetString(result);
  743.         makeDataString.Dispose();
  744.         }
  745.     } // TDescriptor::GetString 
  746.  
  747. //----------------------------------------------------------------------------------------
  748. // TDescriptor::GetDateTimeRec: 
  749. //----------------------------------------------------------------------------------------
  750. DateTimeRec TDescriptor::GetDateTimeRec() const
  751.     {
  752.     DateTimeRec dateTime;
  753.     
  754.     //
  755.     // We'll do our own coercion from typeLongInteger, if necessary.
  756.     // We should really have a coercion handler for this
  757.     //
  758.     if(this->DescriptorType() == typeLongInteger)
  759.         {
  760.         long secsSince1904 = this->GetLong();
  761.         Secs2Date(secsSince1904,&dateTime);
  762.         }
  763.     else
  764.         {
  765.         //
  766.         // Get the time date rec
  767.         //
  768.         this->GetBlock( (Ptr)&dateTime, sizeof(DateTimeRec), typeDateTimeRec);
  769.         }
  770.     
  771.     return dateTime;
  772.     } // TDescriptor::GetDateTimeRec 
  773.  
  774. //----------------------------------------------------------------------------------------
  775. // TDescriptor::GetFSS: 
  776. //----------------------------------------------------------------------------------------
  777. void TDescriptor::GetFSS(FSSpec& spec) const
  778.     {
  779.     this->GetBlock((Ptr)&spec, sizeof(FSSpec), typeFSS);
  780.     } // TDescriptor::GetFSS 
  781.  
  782. //----------------------------------------------------------------------------------------
  783. // InterpretCompareResult:
  784. //
  785. // Given two keys and a comparison opperator, this function determines if
  786. // the comparison between key2 and key1 is true or false.  key1 and key2 should
  787. // be either two long integers representing the various values of the two descriptors
  788. // being compared, or key1 may be set to 0 and key2 set to -1 (key2 < key1), 0
  789. // (key1 == key2) or 1 (key2 > key1).
  790. //
  791. // This function is used by GeneralCompare, which is used by TDescriptor::Compare
  792. //----------------------------------------------------------------------------------------
  793. Boolean InterpretCompareResult(DescType comparisonOperator, long key1, long key2 )
  794.     {
  795.     switch(comparisonOperator)
  796.         {
  797.         case kAEEquals:
  798.             {
  799.             return key1 == key2;
  800.             }
  801.         
  802.         case kASNotEqual:
  803.             {
  804.             return key1 != key2;
  805.             }
  806.         
  807.         case kAEGreaterThan:
  808.             {
  809.             return key1 > key2;
  810.             }
  811.         
  812.         case kAEGreaterThanEquals:
  813.             {
  814.             return key1 >= key2;
  815.             }
  816.         
  817.         case kAELessThan:
  818.             {
  819.             return key1 < key2;
  820.             }
  821.         
  822.         case kAELessThanEquals:
  823.             {
  824.             return key1 <= key2;
  825.             }
  826.         
  827.         //
  828.         // ••• Perhaps we should fail if we don't recognize the comparisonOperator
  829.         //
  830.         default:
  831.             {
  832.             return false;
  833.             }
  834.         }
  835.     } // InterpretCompareResult 
  836.  
  837. //----------------------------------------------------------------------------------------
  838. // GeneralCompare: 
  839. //
  840. // This is a general comparison routine that works on streams of bytes.  It is assumed
  841. // that the data being compared follows the same ordering rules as strings.  The
  842. // 'caseSensitive' flag should always be true for non-string objects, of course.
  843. //----------------------------------------------------------------------------------------
  844. Boolean GeneralCompare(DescType comparisonOperator, Ptr data, Size length, Ptr compareWith, Size comparisonLength, Boolean caseSensitive)
  845.     {
  846.     Boolean comparisonResult = false;
  847.     long i = 0;
  848.         
  849.     switch(comparisonOperator)
  850.         {
  851.         case kAEEquals:        
  852.         case kASNotEqual:
  853.         case kAEGreaterThan:
  854.         case kAEGreaterThanEquals:
  855.         case kAELessThan:
  856.         case kASLessThanOrEqual:
  857.             {
  858.             short intermediateResult = 0;
  859.             Size max = (length < comparisonLength ? length : comparisonLength);
  860.             
  861.             //
  862.             // We have a little bit of code duplication here
  863.             // to make the code run a little faster
  864.             //
  865.             if(caseSensitive)
  866.                 {
  867.                 for(i=0; i < max; ++i)
  868.                     {
  869.                     if(*((unsigned char*)compareWith) > *((unsigned char*)data))
  870.                         {
  871.                         intermediateResult = 1;
  872.                         break;
  873.                         }
  874.                     else if(*((unsigned char*)compareWith) < *((unsigned char*)data))
  875.                         {
  876.                         intermediateResult = -1;
  877.                         break;
  878.                         }
  879.                     ++compareWith;
  880.                     ++data;
  881.                     }
  882.                 }
  883.             else
  884.                 {
  885.                 for(i=0; i < max; ++i)
  886.                     {
  887.                     unsigned char compareWithChar = *((unsigned char*)compareWith);
  888.                     unsigned char dataChar = *((unsigned char*)data);
  889.                     
  890.                     if((compareWithChar >= 'a') && (compareWithChar <= 'z'))
  891.                         compareWithChar = compareWithChar - 'a' + 'A';
  892.                     if((dataChar >= 'a') && (dataChar <= 'z'))
  893.                         dataChar = dataChar - 'a' + 'A';
  894.                         
  895.                     if(compareWithChar > dataChar)
  896.                         {
  897.                         intermediateResult = 1;
  898.                         break;
  899.                         }
  900.                     else if(compareWithChar < dataChar)
  901.                         {
  902.                         intermediateResult = -1;
  903.                         break;
  904.                         }
  905.                     ++compareWith;
  906.                     ++data;
  907.                     }
  908.                 }
  909.             
  910.             if(intermediateResult == 0)
  911.                 intermediateResult = (comparisonLength > length) - (comparisonLength < length);
  912.             
  913.             comparisonResult = InterpretCompareResult(comparisonOperator,0,intermediateResult);
  914.             
  915.             break;
  916.             }
  917.         
  918.         case kAEBeginsWith:
  919.             {
  920.             comparisonResult = GeneralCompare(kAEEquals, data, comparisonLength, compareWith, comparisonLength,caseSensitive);
  921.             break;
  922.             }
  923.             
  924.         case kAEEndsWith:
  925.             {
  926.             i = (length - comparisonLength);
  927.             if(i >= 0)
  928.                 comparisonResult = GeneralCompare(kAEEquals, data + i, comparisonLength, compareWith, comparisonLength,caseSensitive);
  929.             break;
  930.             }
  931.             
  932.         case kAEContains:
  933.             {
  934.             for(i=0;i<=length - comparisonLength;++i)
  935.                 {
  936.                 if(GeneralCompare(kAEEquals, data + i, comparisonLength, compareWith, comparisonLength,caseSensitive))
  937.                     {
  938.                     comparisonResult = true;
  939.                     break;
  940.                     }
  941.                 }
  942.             
  943.             break;
  944.             }
  945.             
  946.         default:
  947.             {
  948.             comparisonResult = false;
  949.             }
  950.         }
  951.     
  952.     return comparisonResult;
  953.     } // GeneralCompare 
  954.  
  955.  
  956. //----------------------------------------------------------------------------------------
  957. // StringContains: 
  958. //----------------------------------------------------------------------------------------
  959. Boolean    StringContains(Str255 thisString, Str255 withString)
  960.     {
  961.     unsigned char thisSize = (unsigned char)thisString[0];
  962.     unsigned char withSize = (unsigned char)withString[0];
  963.  
  964.     if ((thisSize == 0) || (withSize > thisSize))        // quick check
  965.         return false;
  966.  
  967.     Boolean b = false;
  968.     unsigned char* a = &thisString[0];
  969.     unsigned char* last = a + thisSize - withSize + 1;
  970.     do
  971.         {
  972.         b = IUMagIDString(Ptr(++a), Ptr(withString[1]), withSize, withSize);
  973.         }
  974.     while (b && (a < last));
  975.  
  976.     return (b == false);
  977.     } // StringContains 
  978.  
  979. //----------------------------------------------------------------------------------------
  980. // TDescriptor::Compare: 
  981. //----------------------------------------------------------------------------------------
  982. Boolean TDescriptor::Compare(DescType comparisonOperator, Str255 withString) const
  983.     {
  984.     Str255 thisString;
  985.     Size thisSize;
  986.     Size withSize;
  987.     Boolean compareResult = false;
  988.     
  989.     //
  990.     // Fetch a copy of 'thisString' (which we will freely destroy later)
  991.     //
  992.     this->GetString(thisString);
  993.     thisSize = (unsigned char)thisString[0];
  994.     withSize = (unsigned char)withString[0];
  995.  
  996.     switch(comparisonOperator)
  997.         {
  998.         //
  999.         // Check to see if we can find the string anywhere inside
  1000.         //
  1001.         case kAEContains:
  1002.             {
  1003.             long    i;
  1004.             
  1005.             unsigned char* a = &thisString[0];
  1006.             for(i=0;i<thisSize - withSize + 1;++i)
  1007.                 {
  1008.                 *a = (unsigned char)withSize;
  1009.                 compareResult = (IUEqualString(a, withString) == 0);
  1010.                 if(compareResult == true)
  1011.                     break;
  1012.                 ++a;
  1013.                 }
  1014.             }
  1015.             break;
  1016.         
  1017.         //
  1018.         // Relational tests are easy:  use IUCompString
  1019.         //
  1020.         case kAEGreaterThan:
  1021.         case kAEGreaterThanEquals:
  1022.         case kAELessThan:
  1023.         case kASLessThanOrEqual:
  1024.             {
  1025.             compareResult = InterpretCompareResult(comparisonOperator, IUCompString(thisString, withString), 0);
  1026.             }
  1027.             break;
  1028.         
  1029.         //
  1030.         // For AEEndsWith, move the end of the string down to
  1031.         // the beginning of the string, then fall through to
  1032.         // the 'begins with' case
  1033.         //
  1034.         // International allert:  this could clip a two-byte
  1035.         // character in half, but doing so probably won't cause
  1036.         // a problem, since we are looking for exact matches.
  1037.         //
  1038.         case kAEEndsWith:
  1039.             {
  1040.             if(withSize <= thisSize)
  1041.                 BlockMove((Ptr)&thisString[thisSize - withSize + 1],(Ptr)&thisString[1],withSize);
  1042.             }
  1043.             // !!! fall through
  1044.             
  1045.         //
  1046.         // For kAEBeginsWith, set the length of the 'thisString'
  1047.         // to the length of the 'withString' and do an equality test
  1048.         //
  1049.         // International allert:  this could clip a two-byte
  1050.         // character in half, but doing so probably won't cause
  1051.         // a problem, since we are looking for exact matches.
  1052.         //
  1053.         case kAEBeginsWith:
  1054.             {
  1055.             thisString[0] = (unsigned char)withSize;
  1056.             }
  1057.             // !!! fall through...
  1058.         
  1059.         //
  1060.         // kAEEquals and kASNotEqual must come immediately after
  1061.         // begins with and ends with
  1062.         //
  1063.         case kAEEquals:
  1064.         case kASNotEqual:
  1065.             {
  1066.             compareResult = (IUEqualString(thisString, withString) == 0);
  1067.             if(comparisonOperator == kASNotEqual)
  1068.                 compareResult = !compareResult;
  1069.             }
  1070.             break;
  1071.         
  1072.         //
  1073.         // Shouldn't ever get here...
  1074.         //
  1075.         default:
  1076.             {
  1077.             compareResult = GeneralCompare(comparisonOperator,(Ptr)&thisString[1],thisSize,(Ptr)&withString[1],withSize,false);
  1078.             }
  1079.             break;
  1080.         }
  1081.     
  1082.     return compareResult;
  1083.     } // TDescriptor::Compare 
  1084.  
  1085. //----------------------------------------------------------------------------------------
  1086. // TDescriptor::Compare: 
  1087. //
  1088. // Compare two descriptors.  ComparisonOperator should be one of the following:
  1089. //
  1090. // kAEEquals, kASNotEqual, kAEGreaterThan, kAEGreaterThanEquals, kAELessThan,
  1091. // kASLessThanOrEqual, kAEBeginsWith, kAEEndsWith, or kAEContains
  1092. //----------------------------------------------------------------------------------------
  1093. Boolean TDescriptor::Compare(DescType comparisonOperator, TDescriptor& compareWith) const
  1094.     {
  1095.     Boolean compareResult = false;
  1096.     
  1097.     //
  1098.     // It might be nice to try to do a type coercion here, but for now
  1099.     // we only compare descriptors of the same type
  1100.     //
  1101.     if(this->DescriptorType() != compareWith.DescriptorType())
  1102.         FailErr(errAEEventNotHandled);
  1103.     
  1104.     switch(this->DescriptorType())
  1105.         {
  1106.         case typeChar:
  1107.             {
  1108.             Str255 withString;
  1109.  
  1110.             compareWith.GetString(withString);
  1111.             compareResult = this->Compare(comparisonOperator, withString);
  1112.  
  1113.             break;
  1114.             }
  1115.             break;
  1116.         
  1117.         //
  1118.         // We convert DateTimeRecs into integers for comparison so that
  1119.         // someone can supply "the 300th day of January", and it will compare
  1120.         // as being larger than "the 2nd day of February".
  1121.         //
  1122.         // Begins with, ends with and contains are meaningless for dates, though.
  1123.         //
  1124.         case typeLongInteger:
  1125.         case typeDateTimeRec:
  1126.             {            
  1127.             compareResult = InterpretCompareResult(comparisonOperator, this->GetLong(), compareWith.GetLong() );
  1128.             }
  1129.             break;
  1130.         
  1131.         //
  1132.         // If we don't know what type this is, we'll do our best
  1133.         // to do a generic comparison.  This can result in some
  1134.         // very stupid comparisons, but that's life.
  1135.         //
  1136.         default:
  1137.             {
  1138.             Handle        withHandle = compareWith.DataHandle();
  1139.             short        thisState;
  1140.             short        withState;
  1141.             Size        thisSize;
  1142.             Size        withSize;
  1143.             
  1144.             thisState = HGetState(fDataHandle);
  1145.             withState = HGetState(withHandle);
  1146.             thisSize = GetHandleSize(fDataHandle);
  1147.             withSize = GetHandleSize(withHandle);
  1148.             
  1149.             compareResult = GeneralCompare(comparisonOperator,(Ptr)*fDataHandle,thisSize,(Ptr)*withHandle,withSize,true);
  1150.             
  1151.             HSetState(fDataHandle,thisState);
  1152.             HSetState(withHandle,withState);
  1153.             }
  1154.             break;
  1155.         }
  1156.         
  1157.     return compareResult;
  1158.     } // TDescriptor::Compare
  1159.  
  1160. //========================================================================================
  1161. // CLASS TDescriptorLoop
  1162. //
  1163. // The class TDescriptorLoop is used by the macro FOREACHDESCRIPTOR.  Note that the
  1164. // descriptor returned by "Next" is a copy that must be disposed of by the programmer.
  1165. //
  1166. // We could have TDescriptorLoop keep track of the descriptor it created, and have it
  1167. // dispose it when done.  This would necessitate an 'orphan' method, though, in case
  1168. // someone else wanted to adopt the descriptor.
  1169. //========================================================================================
  1170.  
  1171. //----------------------------------------------------------------------------------------
  1172. // TDescriptorLoop::Next: 
  1173. //
  1174. // If 'key' is not nil, it is filled in with the keyword from the i'th item of the
  1175. // list (if the list is a record)
  1176. //
  1177. // If 'dataHandle' is not nil, it is filled in with the data handle from the i'th
  1178. // item of the list.  This is only done to be nice to the FOREACHTOKEN macro.
  1179. //----------------------------------------------------------------------------------------
  1180. Boolean TDescriptorLoop::Next(TDescriptor& d, AEKeyword* key, Handle* dataHandle)
  1181.     {
  1182.     Boolean moreToDo = false;
  1183.     
  1184.     //
  1185.     // Set up on the first time through the loop
  1186.     //
  1187.     if(fIndex == 0)
  1188.         {
  1189.         fCount = fDescriptorList->CountItems();
  1190.         if(d.IsNullDescriptor() == false)
  1191.             {
  1192.             DebugStr("\pTDescriptorLoop::Next:  'd' was not null on first iteration!");
  1193.             FailErr(errAEEventFailed);
  1194.             }
  1195.         }
  1196.  
  1197.     //
  1198.     // Advance to the next item in the list...
  1199.     //
  1200.     fIndex++;
  1201.     
  1202.     //
  1203.     // Dispose of the 'd' from last time through the loop
  1204.     //
  1205.     d.Dispose();
  1206.     
  1207.     //
  1208.     // Are there still items in the list?
  1209.     //
  1210.     if (fIndex <= fCount)
  1211.         {
  1212.         //
  1213.         // At this point, we could check to see if 'fDescriptorList' actually
  1214.         // points to something that is _not_ a list; if so, we coule return a
  1215.         // _reference_ to the single object, and set a field that indicates that
  1216.         // 'd' is a reference, and should not be disposed next time through the
  1217.         // loop.  The reason we do not do this is that 'd' will be disposed by
  1218.         // the client code if there is a failure, and there is no good way for
  1219.         // the client to know if d is a reference or not.  We could remember
  1220.         // what 'd' was and clean it up in our destructor, but failures can
  1221.         // cause our TDescriptorLoop object to be orphaned without ever being
  1222.         // destructed.
  1223.         //
  1224.         d = fDescriptorList->GetNthDescriptor(fIndex, typeWildCard, key);
  1225.         
  1226.         moreToDo = true;
  1227.         }
  1228.     //
  1229.     // No more items, clean up
  1230.     //
  1231.     else
  1232.         {
  1233.         if(key != nil)
  1234.             *key = typeNull;
  1235.         d.MakeNull();
  1236.         }
  1237.     
  1238.     //
  1239.     // Fill in the 'dataHandle' parameter if it was passed in.
  1240.     // (We only do this to make life easy for the FOREACHTOKEN macro)
  1241.     //
  1242.     if(dataHandle != nil)
  1243.         *dataHandle = d.DataHandle();
  1244.     
  1245.     return moreToDo;
  1246.     } // TDescriptorLoop::Next 
  1247.  
  1248.  
  1249. //----------------------------------------------------------------------------------------
  1250. // TDescriptor::MakeEmptyList:
  1251. //
  1252. // Make an empty descriptor list.  It is usually not necessary to make an empty list,
  1253. // because all of the TDescriptor routines will interpret null descriptors as
  1254. // empty lists.  Sometimes it is necessary to return an empty list as the result of
  1255. // an AppleEvent handler, though, and in this case a null descriptor is _not_ equivalent.
  1256. //
  1257. // By default, include no factored data and make an AEList.
  1258. //----------------------------------------------------------------------------------------
  1259. void TDescriptor::MakeEmptyList()
  1260.     {
  1261.     this->CreateList(kMakeAEList);
  1262.     } // TDescriptor::MakeEmptyList 
  1263.  
  1264. //----------------------------------------------------------------------------------------
  1265. // TDescriptor::MakeList: 
  1266. //
  1267. // If this descriptor is null, an empty list is created.  If this descriptor is not
  1268. // empty, then a list is created and this descriptor is placed inside it.  If this
  1269. // descriptor is already a list, then no action is taken.
  1270. //
  1271. // ••• DANGER:  Does a coerce-in-place!
  1272. //----------------------------------------------------------------------------------------
  1273. void TDescriptor::MakeList()
  1274.     {
  1275.     if(this->IsNullDescriptor())
  1276.         {
  1277.         this->CreateList();
  1278.         }
  1279.     else if(this->DescriptorType() != typeAEList)
  1280.         {
  1281.         this->CoerceInPlace(typeAEList);
  1282.         }
  1283.     } // TDescriptor::MakeList 
  1284.     
  1285. //----------------------------------------------------------------------------------------
  1286. // TDescriptor::CountItems:
  1287. //
  1288. // Count the items in a descriptor list. If this descriptor is not of typeAEList, then it
  1289. // only has one item, and if the descriptor is null, then it has no items.
  1290. //----------------------------------------------------------------------------------------
  1291. long TDescriptor::CountItems() const
  1292.     {
  1293.     long items = 1;
  1294.     if(this->IsNullDescriptor())
  1295.         items = 0;
  1296.     else if((this->DescriptorType() == typeAEList) || (this->DescriptorType() == typeAERecord))
  1297.         FailErr(AECountItems(*this, &items));
  1298.     return items;
  1299.     } // TDescriptor::CountItems 
  1300.  
  1301. //----------------------------------------------------------------------------------------
  1302. // TDescriptor::GetNthDescriptor:
  1303. //
  1304. // Get the indexed descriptor from an event.  This method will fail if given an index
  1305. // less than one or greater than the count returned by TDescriptor::CountItems.
  1306. // The descriptor returned is _always_ a copy that must be disposed of with
  1307. // TDescriptor::Dispose.
  1308. //----------------------------------------------------------------------------------------
  1309. TDescriptor TDescriptor::GetNthDescriptor(long index, DescType desiredType, AEKeyword* key) const
  1310.     {
  1311.     TDescriptor descriptor;
  1312.     AEKeyword ignoreKey;
  1313.     
  1314.     if(key == nil)
  1315.         key = &ignoreKey;
  1316.         
  1317.     //
  1318.     // We can "GetNthDescriptor" on an item that is not of typeAEList
  1319.     // if the index is one; we do this by cloning ourself
  1320.     // (n.b. AERecords are also lists)
  1321.     //
  1322.     if((DescriptorType() != typeAEList) && (DescriptorType() != typeAERecord))
  1323.         {
  1324.         if(index != 1)
  1325.             FailErr(-1);        // ••• index out of range
  1326.         
  1327.         *key = typeWildCard; 
  1328.         descriptor = this->Clone();
  1329.         }
  1330.     else
  1331.         {
  1332.         FailErr(AEGetNthDesc(*this, index, desiredType, key, descriptor));
  1333.         }
  1334.     
  1335.     return descriptor;
  1336.     } // TDescriptor::GetNthDescriptor 
  1337.  
  1338. //----------------------------------------------------------------------------------------
  1339. // TDescriptor::AddDescriptor:
  1340. //
  1341. // Add data to a descriptor list at a specified index, replacing any item already stored
  1342. // at that position.
  1343. //----------------------------------------------------------------------------------------
  1344. void TDescriptor::AddDescriptor(long index, TDescriptor& data)
  1345.     {
  1346.     //
  1347.     // If the list is completely empty, just put the data directly into
  1348.     // this descriptor (don't make a list)
  1349.     //
  1350.     if(this->IsNullDescriptor())
  1351.         {
  1352.         this->CopyDesc(data);
  1353.         }
  1354.     else
  1355.         {
  1356.         // If we're not a list yet, we'd better make ourselves one now.
  1357.         if(this->DescriptorType() != typeAEList)
  1358.             this->MakeList();
  1359.         FailErr(AEPutDesc(*this, index, data));
  1360.         }
  1361.     } // TDescriptor::AddDescriptor 
  1362.  
  1363. //----------------------------------------------------------------------------------------
  1364. // TDescriptor::AddDescriptor:
  1365. //
  1366. // Add data to a descriptor list at the end of the list
  1367. //----------------------------------------------------------------------------------------
  1368. void TDescriptor::AddDescriptor(TDescriptor& data)
  1369.     {
  1370.     this->AddDescriptor(0,data);
  1371.     } // TDescriptor::AddDescriptor 
  1372.  
  1373. //----------------------------------------------------------------------------------------
  1374. // TDescriptor::AddData: 
  1375. //----------------------------------------------------------------------------------------
  1376. void TDescriptor::AddData(long index, DescType descType, Ptr data, Size length)
  1377.     {
  1378.     //
  1379.     // If the list is completely empty, we'd better make an empty list
  1380.     // (the type coercion from null to typeAEList probably works,
  1381.     // but I have not tested it yet; the following two lines may
  1382.     // be superfluous)
  1383.     //
  1384.     if(this->IsNullDescriptor())
  1385.         this->MakeEmptyList();
  1386.     
  1387.     //
  1388.     // If we're not a list yet, we'd better make ourselves one now.
  1389.     //
  1390.     if(this->DescriptorType() != typeAEList)
  1391.         this->CoerceInPlace(typeAEList);
  1392.     
  1393.     //
  1394.     // Put the data into the list
  1395.     //
  1396.     FailErr(AEPutPtr(*this,index,descType,data,length));
  1397.     } // TDescriptor::AddData 
  1398.  
  1399. //----------------------------------------------------------------------------------------
  1400. // TDescriptor::AddData: 
  1401. //----------------------------------------------------------------------------------------
  1402. void TDescriptor::AddData(DescType descType, Ptr data, Size length)
  1403.     {
  1404.     this->AddData(0,descType,data,length);
  1405.     } // TDescriptor::AddData 
  1406.  
  1407. //----------------------------------------------------------------------------------------
  1408. // TDescriptor::AddLong: 
  1409. //----------------------------------------------------------------------------------------
  1410. void TDescriptor::AddLong(long number)
  1411.     {
  1412.     this->AddData(typeLongInteger,(Ptr)&number,sizeof(long));
  1413.     } // TDescriptor::AddLong 
  1414.  
  1415. //----------------------------------------------------------------------------------------
  1416. // TDescriptor::AddType: 
  1417. //----------------------------------------------------------------------------------------
  1418. void TDescriptor::AddType(DescType descType)
  1419.     {
  1420.     this->AddData(typeType,(Ptr)&descType,sizeof(DescType));
  1421.     } // TDescriptor::AddType 
  1422.  
  1423. //----------------------------------------------------------------------------------------
  1424. // TDescriptor::AppendList:
  1425. //
  1426. // Append a list onto the end of this one.  The list passed in may be a null descriptor
  1427. // or a single item as well as a list.
  1428. //----------------------------------------------------------------------------------------
  1429. void TDescriptor::AppendList(const TDescriptor& list)
  1430.     {
  1431.     TDescriptor descriptor;
  1432.     OSErr err = noErr;
  1433.     
  1434.     //
  1435.     // If this descriptor is a null descriptor, then we just want
  1436.     // to copy the incoming list.
  1437.     //
  1438.     // In the past we did not do this check, which resulted in
  1439.     // the unfortunate side effect of converting a single-item
  1440.     // list into a single (non-list) descriptor whenever said
  1441.     // list was 'AppendList'ed into an empty list.  While this
  1442.     // may be more efficient, it really hosed us over in the case
  1443.     // of GetData on the selection property, which is SUPPOSED
  1444.     // to return a single-item list (as opposed to a single
  1445.     // descriptor) if there is only one item in the list.  (This
  1446.     // is quite different from most other objects, which are
  1447.     // supposed to return single descriptors instead of single-
  1448.     // item lists whenever there is only one object in the result.)
  1449.     //
  1450.     if(this->IsNullDescriptor())
  1451.         {
  1452.         this->CopyDesc(list);
  1453.         }
  1454.     else if(list.IsNullDescriptor() == false)
  1455.         {
  1456.         Try
  1457.             {
  1458.             FOREACHDESCRIPTOR(&list, descriptor)
  1459.                 {
  1460.                 this->AddDescriptor(descriptor);
  1461.                 }
  1462.             }
  1463.         Catch(err)
  1464.             {
  1465.             descriptor.Dispose();
  1466.             Throw(err);
  1467.             }
  1468.         }
  1469.     } // TDescriptor::AppendList 
  1470.  
  1471. //----------------------------------------------------------------------------------------
  1472. // TDescriptor::AdoptList: 
  1473. //----------------------------------------------------------------------------------------
  1474. void TDescriptor::AdoptList(TDescriptor* list)
  1475.     {
  1476.     if(this->IsNullDescriptor())
  1477.         {
  1478.         this->AdoptDesc(*list);
  1479.         }
  1480.     else
  1481.         {
  1482.         this->AppendList(*list);
  1483.         list->Dispose();
  1484.         }
  1485.     } // TDescriptor::AdoptList 
  1486.  
  1487. //----------------------------------------------------------------------------------------
  1488. // TDescriptor::MakeAERecord:
  1489. //
  1490. // CreateList creates both AERecords and AELists.
  1491. //----------------------------------------------------------------------------------------
  1492. void TDescriptor::MakeAERecord()
  1493.     {
  1494.     this->CreateList(kMakeAERecord);
  1495.     } // TDescriptor::MakeAERecord 
  1496.     
  1497. //----------------------------------------------------------------------------------------
  1498. // TDescriptor::GetDescriptor:
  1499. //
  1500. // Get the ae descriptor from the event. If the desired type is not specified, it
  1501. // defaults to typeWildCard
  1502. //----------------------------------------------------------------------------------------
  1503. TDescriptor TDescriptor::GetDescriptor(AEKeyword key, DescType desiredType)
  1504.     {
  1505.     TDescriptor result;
  1506.  
  1507.     //
  1508.     // n.b. This object must be typeAERecord or typeAppleEvent, or this
  1509.     // call will fail.  Other record-like descriptors (e.g. object specifiers)
  1510.     // cannot be passed to AEGetParamDesc.
  1511.     //
  1512.     FailErr(AEGetParamDesc(*this, key, desiredType, (AEDesc *) &result));
  1513.     
  1514.     return result;
  1515.     } // TDescriptor::GetDescriptor 
  1516.     
  1517. //----------------------------------------------------------------------------------------
  1518. // TDescriptor::GetOptionalParameter:
  1519. //
  1520. // Like 'GetDescriptor, but returns a null descriptor if the specified parameter could not
  1521. // be extracted.
  1522. //----------------------------------------------------------------------------------------
  1523. TDescriptor TDescriptor::GetOptionalParameter(AEKeyword key, DescType desiredType)
  1524.     {
  1525.     TDescriptor result;
  1526.     OSErr err = noErr;
  1527.  
  1528.     //
  1529.     // It's probably not necessary to call MakeNull if there is
  1530.     // an error, but we might as well be safe (paranoid?).
  1531.     //
  1532.     err = AEGetParamDesc(*this, key, desiredType, (AEDesc *) &result);
  1533.     if(err != noErr)
  1534.         result.MakeNull();
  1535.     
  1536.     return result;
  1537.     } // TDescriptor::GetOptionalParameter 
  1538.  
  1539. //----------------------------------------------------------------------------------------
  1540. // TDescriptor::GetParameterPtr:
  1541. //
  1542. // Get the ae descriptor from the record
  1543. //----------------------------------------------------------------------------------------
  1544. void TDescriptor::GetParameterPtr(AEKeyword key, DescType desiredType, DescType *typeCode, Ptr dataPtr, Size maximumSize, Size *actualSize)
  1545.     {
  1546.     //
  1547.     // n.b. This object must be typeAERecord or typeAppleEvent, or this
  1548.     // call will fail.  Other record-like descriptors (e.g. object specifiers)
  1549.     // cannot be passed to AEGetParamPtr.
  1550.     //
  1551.     FailErr(AEGetParamPtr(*this, key, desiredType, typeCode, dataPtr, maximumSize, actualSize));
  1552.     } // TDescriptor::GetParameterPtr 
  1553.     
  1554. //----------------------------------------------------------------------------------------
  1555. // TDescriptor::GetLongParameter:
  1556. //
  1557. // Get the first longword of data from a parameter coerced to the specified type
  1558. // (usually typeLongInteger)
  1559. //----------------------------------------------------------------------------------------
  1560. long TDescriptor::GetLongParameter(AEKeyword key, DescType desiredType)
  1561.     {
  1562.     long actualSize;
  1563.     DescType typeCode;
  1564.     long result = 0;
  1565.         
  1566.     GetParameterPtr(key, desiredType, &typeCode, (Ptr) &result, sizeof(long), &actualSize);
  1567.     
  1568.     return result;
  1569.     } // TDescriptor::GetLongParameter 
  1570.     
  1571. //----------------------------------------------------------------------------------------
  1572. // TDescriptor::GetShortParameter:
  1573. //
  1574. // Get the first shortword of data from a parameter coerced to the specified type
  1575. // (usually typeShortInteger)
  1576. //----------------------------------------------------------------------------------------
  1577. short TDescriptor::GetShortParameter(AEKeyword key, DescType desiredType)
  1578.     {
  1579.     long actualSize;
  1580.     DescType typeCode;
  1581.     short result = 0;
  1582.     GetParameterPtr(key, desiredType, &typeCode, (Ptr) &result, sizeof(short), &actualSize);
  1583.     
  1584.     return result;
  1585.     } // TDescriptor::GetShortParameter 
  1586.     
  1587. //----------------------------------------------------------------------------------------
  1588. // TDescriptor::GetDirectObject:
  1589. //
  1590. // Get the direct object of the event
  1591. //----------------------------------------------------------------------------------------
  1592. TDescriptor TDescriptor::GetDirectObject()
  1593.     {
  1594.     return GetDescriptor(keyDirectObject);
  1595.     } // TDescriptor::GetDirectObject 
  1596.  
  1597. //----------------------------------------------------------------------------------------
  1598. // TDescriptor::GetErrorCode:
  1599. //
  1600. // Get an error code
  1601. //----------------------------------------------------------------------------------------
  1602. long TDescriptor::GetErrorCode()
  1603.     {
  1604.     long error = noErr;
  1605.     
  1606.     Try
  1607.         {
  1608.         error = GetLongParameter(keyErrorNumber);
  1609.         }
  1610.     
  1611.     return error;
  1612.     } // TDescriptor::GetErrorCode 
  1613.  
  1614. //----------------------------------------------------------------------------------------
  1615. // TDescriptor::PutDescriptor:
  1616. //
  1617. // Put a TDescriptor into the event
  1618. //----------------------------------------------------------------------------------------
  1619. void TDescriptor::PutDescriptor(AEKeyword key, TDescriptor data)
  1620.     {
  1621.     FailErr(AEPutParamDesc(*this, key, data));
  1622.     } // TDescriptor::PutDescriptor 
  1623.     
  1624. //----------------------------------------------------------------------------------------
  1625. // TDescriptor::PutParameterPtr:
  1626. //
  1627. // Create a descriptor from a block of data and insert it into the record
  1628. //----------------------------------------------------------------------------------------
  1629. void TDescriptor::PutParameterPtr(AEKeyword key, DescType typeCode, Ptr dataPtr, Size dataSize)
  1630.     {
  1631.     FailErr(AEPutParamPtr(*this, key, typeCode, dataPtr, dataSize));
  1632.     } // TDescriptor::PutParameterPtr 
  1633.  
  1634. //----------------------------------------------------------------------------------------
  1635. // TDescriptor::PutParameterHandle: 
  1636. //----------------------------------------------------------------------------------------
  1637. void TDescriptor::PutParameterHandle(AEKeyword key, DescType typeCode, Handle dataHandle)
  1638.     {
  1639.     short        handleState;
  1640.     Size        dataSize;
  1641.     
  1642.     //
  1643.     // Feature:  if the dataHandle is nil, nothing is added to the AERecord.
  1644.     //
  1645.     if(dataHandle != nil)
  1646.         {
  1647.         handleState = HGetState(dataHandle);
  1648.         HLock(dataHandle);
  1649.         dataSize = GetHandleSize(dataHandle);
  1650.         
  1651.         this->PutParameterPtr(key,typeCode,*dataHandle,dataSize);
  1652.         
  1653.         HSetState(dataHandle,handleState);
  1654.         }
  1655.     } // TDescriptor::PutParameterHandle 
  1656.     
  1657. //----------------------------------------------------------------------------------------
  1658. // TDescriptor::PutLongParameter:
  1659. //
  1660. // Put a long parameter (type specified)
  1661. //----------------------------------------------------------------------------------------
  1662. void TDescriptor::PutLongParameter(AEKeyword key, DescType typeCode, long data)
  1663.     {
  1664.     this->PutParameterPtr(key, typeCode, (Ptr) &data, sizeof(long));
  1665.     } // TDescriptor::PutLongParameter 
  1666.     
  1667. //----------------------------------------------------------------------------------------
  1668. // TDescriptor::PutLongParameter:
  1669. //
  1670. // Put a long parameter (type is 'typeLongInteger', the most common case)
  1671. //----------------------------------------------------------------------------------------
  1672. void TDescriptor::PutLongParameter(AEKeyword key, long data)
  1673.     {
  1674.     this->PutLongParameter(key,typeLongInteger,data);
  1675.     } // TDescriptor::PutLongParameter 
  1676.     
  1677. //----------------------------------------------------------------------------------------
  1678. // TDescriptor::PutShortParameter:
  1679. //
  1680. // Put a short parameter (type specified)
  1681. //----------------------------------------------------------------------------------------
  1682. void TDescriptor::PutShortParameter(AEKeyword key, DescType typeCode, short data)
  1683.     {
  1684.     this->PutParameterPtr(key, typeCode, (Ptr) &data, sizeof(short));
  1685.     } // TDescriptor::PutShortParameter 
  1686.     
  1687. //----------------------------------------------------------------------------------------
  1688. // TDescriptor::PutShortParameter:
  1689. //
  1690. // Put a short parameter (type is 'typeShortInteger', the most common case)
  1691. //----------------------------------------------------------------------------------------
  1692. void TDescriptor::PutShortParameter(AEKeyword key, short data)
  1693.     {
  1694.     this->PutShortParameter(key,typeShortInteger,data);
  1695.     } // TDescriptor::PutShortParameter 
  1696.  
  1697. //----------------------------------------------------------------------------------------
  1698. // TDescriptor::PutResult: 
  1699. //
  1700. // Put the provided descriptor into the result parameter of this event.  If the data
  1701. // is a null descriptor, then put in an empty list instead.
  1702. //----------------------------------------------------------------------------------------
  1703. void TDescriptor::PutResult(TDescriptor data)
  1704.     {
  1705.     OSErr err = noErr;
  1706.     
  1707.     //
  1708.     // If there's nothing in the data, then insert an empty list.
  1709.     //
  1710.     if(data.IsNullDescriptor())
  1711.         {
  1712.         TDescriptor emptyList;
  1713.  
  1714.         Try
  1715.             {
  1716.             emptyList.MakeEmptyList();
  1717.             this->PutDescriptor(keyAEResult, emptyList);
  1718.             emptyList.Dispose();
  1719.             }
  1720.         Catch(err)
  1721.             {
  1722.             emptyList.Dispose();
  1723.             Throw(err);
  1724.             }
  1725.         }
  1726.     else
  1727.         {
  1728.         this->PutDescriptor(keyAEResult,data);
  1729.         }
  1730.     } // TDescriptor::PutResult 
  1731.     
  1732. //----------------------------------------------------------------------------------------
  1733. // TDescriptor::PutErrorCode:
  1734. //
  1735. // Put an error code
  1736. //----------------------------------------------------------------------------------------
  1737. void TDescriptor::PutErrorCode(long theErr)
  1738.     {
  1739.     this->PutLongParameter(keyErrorNumber,theErr);
  1740.     } // TDescriptor::PutErrorCode 
  1741.  
  1742. //----------------------------------------------------------------------------------------
  1743. // TDescriptor::Resolve: 
  1744. //----------------------------------------------------------------------------------------
  1745. TTokenDescriptor TDescriptor::Resolve()
  1746.     {
  1747.     return TDescriptor::Resolve(fCallbackFlags);
  1748.     } // TDescriptor::Resolve 
  1749.  
  1750. //----------------------------------------------------------------------------------------
  1751. // TDescriptor::Resolve:
  1752. //
  1753. // Resolves a list of object specifiers into a list of tokens.  A null descriptor will
  1754. // resolve to a token to the null container.
  1755. //
  1756. // n.b. AEResolve will return an error if you pass it a null descriptor; this is why
  1757. //        we include 'magic' checking for null descriptors here.
  1758. //----------------------------------------------------------------------------------------
  1759. TTokenDescriptor TDescriptor::Resolve(short callbackFlags)
  1760.     {
  1761.     TTokenDescriptor resolvedToken;
  1762.     TTokenDescriptor intermediate;
  1763.     TDescriptor descriptor;
  1764.     
  1765.     //
  1766.     // First:  special checking for null descriptors
  1767.     //
  1768.     if(this->IsNullDescriptor())
  1769.         {
  1770.         resolvedToken = CreateNullContainerToken();
  1771.         }
  1772.     //
  1773.     // Next, process non-lists
  1774.     //
  1775.     else if(this->DescriptorType() != typeAEList)
  1776.         {
  1777.         //
  1778.         // If a pre-resolve proc was installed, then call it.
  1779.         //
  1780.         // The Scriptable Finder uses this for resolving token
  1781.         // types that AEResolve does not recognize (e.g. alias
  1782.         // records)
  1783.         //
  1784.         if(gPreResolveProc != nil)
  1785.             {
  1786.             resolvedToken = (*gPreResolveProc)(*this);
  1787.             }
  1788.  
  1789.         //
  1790.         // If the pre-resolve proc did not resolve the token,
  1791.         // then call AEResolve
  1792.         //
  1793.         if(resolvedToken.IsNullDescriptor())
  1794.             FailErr(AEResolve(*this, callbackFlags, resolvedToken));
  1795.         }
  1796.     //
  1797.     // If we have a list, try to resolve each element of the list in turn
  1798.     //
  1799.     else
  1800.         {
  1801.         OSErr err = noErr;
  1802.         
  1803.         Try
  1804.             {
  1805.             FOREACHDESCRIPTOR(this, descriptor)
  1806.                 {
  1807.                 //
  1808.                 // We do not want to dispose of the intermediate token descriptor
  1809.                 // because its data is adopted by the 'result' token descriptor.
  1810.                 //
  1811.                 intermediate = descriptor.Resolve(callbackFlags);
  1812.                 resolvedToken.AdoptToken(intermediate);
  1813.                 intermediate.MakeNull();
  1814.                 }
  1815.             }
  1816.         Catch(err)
  1817.             {
  1818.             descriptor.Dispose();
  1819.             intermediate.DisposeToken();
  1820.             resolvedToken.DisposeToken();
  1821.             Throw(err);
  1822.             }
  1823.         }
  1824.     
  1825.     return resolvedToken;
  1826.     } // TDescriptor::Resolve 
  1827.  
  1828.  
  1829. //========================================================================================
  1830. // CLASS TAEvent
  1831. //
  1832. // AppleEvents are just like AERecords, but they can contain attributes as well as
  1833. // parameters.
  1834. //========================================================================================
  1835.  
  1836.  
  1837. //----------------------------------------------------------------------------------------
  1838. // TAEvent::TAEvent: 
  1839. //----------------------------------------------------------------------------------------
  1840. TAEvent::TAEvent()
  1841.     {
  1842.  
  1843.     } // TAEvent::TAEvent 
  1844.  
  1845.  
  1846. //----------------------------------------------------------------------------------------
  1847. // TAEvent::MakeAppleEvent: 
  1848. //----------------------------------------------------------------------------------------
  1849. void TAEvent::MakeAppleEvent(AEEventClass eventClass, AEEventID eventID,
  1850.                         const TDescriptor& target, short returnID, long transactionID)
  1851.     {
  1852.     FailErr(AECreateAppleEvent(eventClass, eventID,
  1853.                         (const AEAddressDesc *) &target, returnID, transactionID, *this));
  1854.     } // TAEvent::MakeAppleEvent 
  1855.  
  1856. //----------------------------------------------------------------------------------------
  1857. // TAEvent::MakeAppleEvent: 
  1858. //----------------------------------------------------------------------------------------
  1859. void TAEvent::MakeAppleEvent(AEEventClass eventClass, AEEventID eventID,
  1860.                         const ProcessSerialNumber& psn, short returnID, long transactionID)
  1861.     {
  1862.     TDescriptor address;
  1863.     address.CopyData(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber));
  1864.     
  1865.     this->MakeAppleEvent(eventClass, eventID, address, returnID, transactionID);
  1866.     
  1867.     address.Dispose();
  1868.     } // TAEvent::MakeAppleEvent 
  1869.  
  1870.  
  1871. #define kCheckAEM            0
  1872. #define kDontUseSelfSend    1
  1873. #define kSelfSendSafe        2
  1874.  
  1875. short gCanUseSelfSend = kCheckAEM;
  1876.  
  1877. //----------------------------------------------------------------------------------------
  1878. // TAEvent::MakeEventAddressedToSelf: 
  1879. //----------------------------------------------------------------------------------------
  1880. void TAEvent::MakeEventAddressedToSelf(AEEventClass eventClass, AEEventID eventID, short returnID, long transactionID)
  1881.     {
  1882.     ProcessSerialNumber current;        // create psn for the Finder
  1883.     current.highLongOfPSN = 0;
  1884.     current.lowLongOfPSN = kCurrentProcess;
  1885.     
  1886.     //
  1887.     // Old versions of the AEM leak memory if send-to-self is used
  1888.     //
  1889.     if(gCanUseSelfSend == kCheckAEM)
  1890.         {
  1891.         long aevtSelector = 0;
  1892.         OSErr err = Gestalt('evnt', &aevtSelector);
  1893.         gCanUseSelfSend = ((aevtSelector & 2) != 0) ? kSelfSendSafe : kDontUseSelfSend;
  1894.         }
  1895.     
  1896.     //
  1897.     // Don't make the self-addressed event unless it is safe to do so
  1898.     //
  1899.     if(gCanUseSelfSend == kSelfSendSafe)
  1900.         {
  1901.         this->MakeAppleEvent(eventClass, eventID, current, returnID, transactionID);
  1902.         }
  1903.     else
  1904.         FailErr(errAEEventNotHandled);
  1905.     } // TAEvent::MakeEventAddressedToSelf 
  1906.  
  1907. //----------------------------------------------------------------------------------------
  1908. // TAEvent::MakeEventAddressedToSystem: 
  1909. //----------------------------------------------------------------------------------------
  1910. void TAEvent::MakeEventAddressedToSystem(AEEventClass eventClass, AEEventID eventID, short returnID, long transactionID)
  1911.     {
  1912.     ProcessSerialNumber systemPSN;        // create psn for the System
  1913.     systemPSN.highLongOfPSN = 0;
  1914.     systemPSN.lowLongOfPSN = kSystemProcess;
  1915.     
  1916.     this->MakeAppleEvent(eventClass, eventID, systemPSN, returnID, transactionID);
  1917.     } // TAEvent::MakeEventAddressedToSystem 
  1918.  
  1919. //----------------------------------------------------------------------------------------
  1920. // TAEvent::Send: 
  1921. //----------------------------------------------------------------------------------------
  1922. void TAEvent::Send( TAEvent* reply,
  1923.                     AESendMode sendMode,
  1924.                     AESendPriority sendPriority,
  1925.                     long timeOutInTicks,
  1926.                     AEIdleUPP idleProc,
  1927.                     AEFilterUPP filterProc)
  1928.     {
  1929.     OSErr err = AESend(*this, *reply, sendMode, sendPriority, timeOutInTicks, idleProc, filterProc);\
  1930.     if((err != errAETimeout) || (timeOutInTicks != 0))
  1931.         FailErr(err);
  1932.     } // TAEvent::Send 
  1933.  
  1934. //----------------------------------------------------------------------------------------
  1935. // TAEvent::Ask
  1936. //
  1937. // Ask a question using future semantics--i.e., send kAEWaitReply with a timeout of 0,
  1938. // then set the reply timeout using the API provided by the futures package.
  1939. //----------------------------------------------------------------------------------------
  1940. TAEvent TAEvent::Ask(long timeoutValue /* = 1200 */, long maxWaitTime /* = 0x7FFFFFFF */, AESendPriority sendPriority /* = kAENormalPriority */)
  1941.     {
  1942.     TAEvent reply;
  1943.     
  1944.     FailErr(AskForFuture(*this, reply, timeoutValue, maxWaitTime, sendPriority));
  1945.     
  1946.     return reply;
  1947.     }
  1948.  
  1949. #define kAEDontExecute 0x2000 // for SendMode, when you just want an event recorded, not executed
  1950.  
  1951. //----------------------------------------------------------------------------------------
  1952. // TAEvent::SendNoExecute: 
  1953. //
  1954. // This routine sends the event with the 'kAEDontExecute' bit set, so that the
  1955. // event will be recorded, but the recipient will not execute it.  The event is
  1956. // also sent 'no reply', since it does not make sense to expect a result from
  1957. // a command that is not actually executed.
  1958. //----------------------------------------------------------------------------------------
  1959. void TAEvent::SendNoExecute()
  1960.     {
  1961.     //
  1962.     // The reply isn't actuall filled in due to the kAENoReply flag
  1963.     //
  1964.     TAEvent reply;
  1965.     Send(&reply, kAENoReply+kAEDontExecute);
  1966.     } // TAEvent::SendNoExecute 
  1967.  
  1968.  
  1969. //----------------------------------------------------------------------------------------
  1970. // TAEvent::SuspendTheCurrentEvent: 
  1971. //----------------------------------------------------------------------------------------
  1972. void TAEvent::SuspendTheCurrentEvent()
  1973.     {
  1974.     FailErr(AESuspendTheCurrentEvent(*this));
  1975.     } // TAEvent::SuspendTheCurrentEvent 
  1976.  
  1977. //----------------------------------------------------------------------------------------
  1978. // TAEvent::ResumeTheCurrentEvent: 
  1979. //----------------------------------------------------------------------------------------
  1980. void TAEvent::ResumeTheCurrentEvent(TAEvent* reply, AEEventHandlerUPP dispatcher, long refCon)
  1981.     {
  1982.     FailErr(AEResumeTheCurrentEvent(*this, *reply, dispatcher, refCon));
  1983.     } // TAEvent::ResumeTheCurrentEvent 
  1984.  
  1985. //----------------------------------------------------------------------------------------
  1986. // TAEvent::SetTheCurrentEvent: 
  1987. //----------------------------------------------------------------------------------------
  1988. void TAEvent::SetTheCurrentEvent()
  1989.     {
  1990.     FailErr(AESetTheCurrentEvent(*this));
  1991.     } // TAEvent::SetTheCurrentEvent 
  1992.  
  1993. //----------------------------------------------------------------------------------------
  1994. // TAEvent::ResetTimer: 
  1995. //
  1996. // Note:    requires that this event be a 'reply' event passed to one of our event
  1997. //            handlers by the AppleEvent manager 
  1998. //----------------------------------------------------------------------------------------
  1999. void TAEvent::ResetTimer()
  2000.     {
  2001.     FailErr(AEResetTimer(*this));
  2002.     } // TAEvent::ResetTimer 
  2003.  
  2004. //----------------------------------------------------------------------------------------
  2005. // TAEvent::SpecifyThatParameterIsOptional: 
  2006. //----------------------------------------------------------------------------------------
  2007. void TAEvent::SpecifyThatParameterIsOptional(AEKeyword theOptionalKeyword)
  2008.     {
  2009.     TDescriptor optionalKeywordsList;
  2010.     TDescriptor optionalKeyword;
  2011.     OSErr err = noErr;
  2012.     
  2013.     Try
  2014.         {
  2015.         //
  2016.         // ◊Script:  We need to test to see if keyOptionalKeywordAttr
  2017.         // already exists, and if so, then just add one more element to
  2018.         // the list that is already inside the event.
  2019.         //
  2020.         optionalKeywordsList.MakeList();
  2021.         optionalKeyword.MakeKeyword(theOptionalKeyword);
  2022.         optionalKeywordsList.AddDescriptor(optionalKeyword);
  2023.         optionalKeyword.Dispose();
  2024.         this->PutAttribute(keyOptionalKeywordAttr, optionalKeywordsList);
  2025.         optionalKeywordsList.Dispose();
  2026.         }
  2027.     Catch(err)
  2028.         {
  2029.         optionalKeyword.Dispose();
  2030.         optionalKeywordsList.Dispose();
  2031.         
  2032.         Throw(err);
  2033.         }
  2034.     } // TAEvent::SpecifyThatParameterIsOptional 
  2035.  
  2036. //----------------------------------------------------------------------------------------
  2037. // TAEvent::GetAttribute: 
  2038. //----------------------------------------------------------------------------------------
  2039. TDescriptor TAEvent::GetAttribute(AEKeyword key, DescType desiredType /* = typeWildCard */)
  2040.     {
  2041.     TDescriptor result;
  2042.     
  2043.     FailErr(AEGetAttributeDesc(*this, key, desiredType, result));
  2044.     
  2045.     return result;
  2046.     } // TAEvent::GetAttribute 
  2047.  
  2048. //----------------------------------------------------------------------------------------
  2049. // TAEvent::GetLongAttribute: 
  2050. //----------------------------------------------------------------------------------------
  2051. long TAEvent::GetLongAttribute(AEKeyword key)
  2052.     {
  2053.     DescType typeCode;
  2054.     long actualSize;
  2055.     long result;
  2056.     
  2057.     FailErr(AEGetAttributePtr(*this, key, typeLongInteger, &typeCode, (Ptr)&result, sizeof(long), &actualSize));
  2058.     
  2059.     return result;
  2060.     } // TAEvent::GetLongAttribute 
  2061.  
  2062. //----------------------------------------------------------------------------------------
  2063. // TAEvent::PutAttribute: 
  2064. //----------------------------------------------------------------------------------------
  2065. void TAEvent::PutAttribute(AEKeyword key, TDescriptor attribute)
  2066.     {
  2067.     FailErr(AEPutAttributeDesc(*this, key, attribute));
  2068.     } // TAEvent::PutAttribute 
  2069.  
  2070. //----------------------------------------------------------------------------------------
  2071. // PutOptionalDescriptor: 
  2072. //----------------------------------------------------------------------------------------
  2073. void TAEvent::PutOptionalDescriptor(AEKeyword key, TDescriptor data)
  2074.     {
  2075.     this->PutDescriptor(key, data);
  2076.     this->SpecifyThatParameterIsOptional(key);
  2077.     } // TAEvent::PutOptionalDescriptor 
  2078.  
  2079. //----------------------------------------------------------------------------------------
  2080. // TAEvent::PutLongAttribute: 
  2081. //----------------------------------------------------------------------------------------
  2082. void TAEvent::PutLongAttribute(AEKeyword key, long attributeValue)
  2083.     {
  2084.     FailErr(AEPutAttributePtr(*this, key, typeLongInteger, (Ptr)&attributeValue, sizeof(long)));
  2085.     } // TAEvent::PutLongAttribute 
  2086.     
  2087.  
  2088. //========================================================================================
  2089. // CLASS TTokenDescriptor
  2090. //
  2091. // The class TTokenDescriptor represents descriptors returned by AEResolve
  2092. //========================================================================================
  2093.  
  2094.  
  2095. //----------------------------------------------------------------------------------------
  2096. // TTokenDescriptor::TTokenDescriptor: 
  2097. //----------------------------------------------------------------------------------------
  2098. TTokenDescriptor::TTokenDescriptor()
  2099.     {
  2100.     fDescriptorType = typeNull;
  2101.     fDataHandle = nil;
  2102.     } // TTokenDescriptor::TTokenDescriptor 
  2103.  
  2104. //----------------------------------------------------------------------------------------
  2105. // TTokenDescriptor::TTokenDescriptor: 
  2106. //----------------------------------------------------------------------------------------
  2107. TTokenDescriptor::TTokenDescriptor(TDescriptor desc)
  2108.     {
  2109.     this->fDescriptorType = desc.DescriptorType();
  2110.     this->fDataHandle = desc.DataHandle();
  2111.     } // TTokenDescriptor::TTokenDescriptor 
  2112.     
  2113. //----------------------------------------------------------------------------------------
  2114. // TTokenDescriptor::DisposeToken:
  2115. //
  2116. // It is very important that token descriptors be disposed of by AEDisposeToken,
  2117. // _not_ AEDisposeDesc.
  2118. //----------------------------------------------------------------------------------------
  2119. void TTokenDescriptor::DisposeToken()
  2120.     {
  2121.     AEDisposeToken(*this);  // Should fail on error?  Probably not.
  2122.  
  2123.     // FailErr(AEDisposeDesc(*this));
  2124.     } // TTokenDescriptor::DisposeToken 
  2125.  
  2126.  
  2127. //----------------------------------------------------------------------------------------
  2128. // TTokenDescriptor::TokenHandle:
  2129. //
  2130. // Return the TTokenObject stored inside the token descriptor
  2131. //----------------------------------------------------------------------------------------
  2132. TAbstractScriptableObject* TTokenDescriptor::TokenHandle()
  2133.     {
  2134.     Handle tokenHandle = this->DataHandle();
  2135.     TAbstractScriptableObject* tokenObject = nil;
  2136.     
  2137.     if((this->DescriptorType() != typeTokenObject) || (tokenHandle == nil))
  2138.         {
  2139.         //
  2140.         // ••• What error code should we fail with here?
  2141.         //
  2142.         FailErr(errAENoSuchObject);
  2143.         }
  2144.     
  2145.     //
  2146.     // tokenHandle is a handle that contains a TTokenObject*,
  2147.     // so it is a pointer to a pointer to a TTokenObject* (wow)
  2148.     //
  2149.     tokenObject = ** ((TAbstractScriptableObject***) tokenHandle);
  2150.     return tokenObject;
  2151.     } // TTokenDescriptor::TokenHandle 
  2152.  
  2153.  
  2154. //----------------------------------------------------------------------------------------
  2155. // TTokenDescriptor::AdoptToken:
  2156. //
  2157. // IMPORTANT: ADOPTS THE TOKEN PASSED TO IT
  2158. //----------------------------------------------------------------------------------------
  2159. void TTokenDescriptor::AdoptToken(TTokenDescriptor& tokenDescriptor)
  2160.     {
  2161.     //
  2162.     // Don't adopt the new token if it is empty
  2163.     //
  2164.     if(tokenDescriptor.IsNullDescriptor() == false)
  2165.         {
  2166.         //
  2167.         // If this descriptor is empty, it is easy to adopt the new token
  2168.         //
  2169.         if( this->IsNullDescriptor() )
  2170.             {
  2171.             TDescriptor::AdoptHandle(tokenDescriptor.DescriptorType(), tokenDescriptor.DataHandle() );
  2172.             tokenDescriptor.MakeNull();
  2173.             }
  2174.         else
  2175.             {
  2176.             TAbstractScriptableObject* tokenObject = tokenDescriptor.TokenHandle();
  2177.             this->AdoptToken(tokenObject);
  2178.             
  2179.             //
  2180.             // n.b.    'Dispose', not 'DisposeToken'.  The token that
  2181.             // was formerly contained in tokenDescriptor is now referenced
  2182.             // in 'this' token descriptor, so it would be a bad idea to
  2183.             // delete it.
  2184.             //
  2185.             tokenDescriptor.Dispose();
  2186.             }
  2187.         }
  2188.     } // TTokenDescriptor::AdoptToken 
  2189.  
  2190. //----------------------------------------------------------------------------------------
  2191. // TTokenDescriptor::AdoptToken: 
  2192. //----------------------------------------------------------------------------------------
  2193. void TTokenDescriptor::AdoptToken(TAbstractScriptableObject* tokenObject)
  2194.     {
  2195.     //
  2196.     // Don't adopt the new token if it is not a valid object
  2197.     //
  2198.     if(tokenObject != nil)
  2199.         {
  2200.         //
  2201.         // If this descriptor is empty, then create a new
  2202.         // token descriptor to hold a pointer to the tokenObject.
  2203.         //
  2204.         if(this->IsNullDescriptor() )
  2205.             {
  2206.             Handle newHandle = NewHandle( sizeof(Ptr) );
  2207.             ** ((TAbstractScriptableObject***)newHandle) = tokenObject;
  2208.             
  2209.             TDescriptor::AdoptHandle(typeTokenObject, newHandle);
  2210.             }
  2211.         //
  2212.         // If there is already something here, then we need
  2213.         // to somehow merge the two tokens together.  In the
  2214.         // Scriptable Finder, we want to create a mark token
  2215.         // to do the merge.  However, MoreAEM does not depend
  2216.         // on files such as MarkToken.h which are outside of
  2217.         // the Blue folder.  Therefore, we call a callback proc
  2218.         // to fill in the mark token.  The callback proc is
  2219.         // installed in InitializeScriptability.
  2220.         //
  2221.         else
  2222.             {
  2223.             if(gMergeTokensProc == nil)
  2224.                 FailErr(errAEEventNotHandled);
  2225.                 
  2226.             //
  2227.             // The MergeTokensProc takes two TAbstractScriptableObject*'s
  2228.             // and merges them into another TAbstractScriptableObject*
  2229.             // (which adopts the two original tokens).
  2230.             //
  2231.             TAbstractScriptableObject* mergedTokens = (*gMergeTokensProc)(this->TokenHandle(), tokenObject);
  2232.  
  2233.             Handle tokenHandle = this->DataHandle();
  2234.             ** ((TAbstractScriptableObject***) tokenHandle) = mergedTokens;
  2235.             }
  2236.         }
  2237.     } // TTokenDescriptor::AdoptToken 
  2238.  
  2239.  
  2240. #pragma segment CFrontCruft
  2241.